<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Document</title>
	</head>
	<style>
		* {
			padding: 0;
			margin: 0;
			box-sizing: border-box;
		}
		html,
		body {
			width: 100%;
			height: 100%;
			background-color: black;
			overflow: hidden;
		}
		#app {
			margin-top: 20px;
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
			background-color: transparent;
		}
		.container {
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
		}
		li {
			position: absolute;
			list-style: none;
			top: 0;
			left: 0;
			display: block;
			text-align: center;
			width: 50px;
			line-height: 50px;
			background: red;
			color: #fff;
			font-size: 1.5em;
			border-radius: 4px;
		}
		.score {
			text-align: center;
			line-height: 45px;
		}
		.gamLeve {
			text-align: center;
			line-height: 45px;
			font-size: 1.5em;
			color: red;
			margin-right: 15px;
		}
		.history {
			float: left;
			position: relative;
			left: 15%;
			line-height: 45px;
			font-size: 1.5em;
		}
		.title {
			position: fixed;
			width: 100%;
			top: 0;
			text-align: center;
			height: 60px;
			color: #fff;
			z-index: 5;
		}

		#canvas {
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
		}
	</style>
	<canvas id="canvas"></canvas>
	<div class="container">
		<div class="title">
			<span class="history"></span>
			<span class="gamLeve"></span>
			<span class="score"></span>
			<span class="chance"></span>
		</div>
		<div id="app"></div>
	</div>

	<body>
		<script src="index.js"></script>
		<script>
			const app = document.querySelector('#app')
			const scores = document.querySelector('.score')
			const chance = document.querySelector('.chance')
			const currentGamLeve = document.querySelector('.gamLeve')
			const history = document.querySelector('.history')
			const container = document.querySelector('.container')
			// 动态设置宽高
			setHW()
			let showCahr = [] // 页面展示的字符集合
			let randomChat = generateBig() // 生成26个字母
			let createCharTimer = null //存放定时器
			let maximum = 10 // 页面展示的最大数量
			let score = 0
			let maxErrorNum = 5
			let lastLeftPostion = [] // 记录生成元素的left值,避免元素重叠
			let base = app.offsetWidth / maximum
			let gamLeveTxt = '普通'
			let downloadingSpeed = 5 // 下降速度
			let gamLeveScore = [
				// 游戏参数配置 参照表
				{
					id: 1,
					gamLeve: '普通',
					gamLeveScore: 5,
					speed: 5,
					maximum: 10,
				},
				{
					id: 2,
					gamLeve: '困难',
					gamLeveScore: 10,
					speed: 7,
					maximum: 5,
				},
				{
					id: 3,
					gamLeve: '炼狱',
					gamLeveScore: 15,
					speed: 10,
					maximum: 10,
				},
			] // 游戏难度对应的分数
			const stroeKdy = 'LLVYRGAMSCORE'
			let TopScore = getItem(stroeKdy) || 0
			// 动态设置宽高
			function setHW() {
				container.style.width = window.innerWidth + 'px'
				container.style.height = window.innerHeight + 'px'
				app.style.width = window.innerWidth + 'px'
				app.style.height = window.innerHeight + 'px'
			}
			// 检测 窗口变化 重新设置宽高
			window.addEventListener('resize', function () {
				setHW()
				// 重置基准值
				base = app.offsetWidth / maximum
			})
			// 创建字符串
			function createChar() {
				if (createCharTimer) clearInterval(createCharTimer)
				createCharTimer = setInterval(() => {
					if (showCahr.length < maximum) {
						// 创建元素
						const li = document.createElement('li')
						// 创建字符串 字符串不能重复
						let str = randomChat[getRandom(0, randomChat.length - 1)]
						// 字符不能重复
						while (showCahr.includes(str)) {
							str = randomChat[getRandom(0, randomChat.length - 1)]
						}
						// 生成的字符串添加到页面展示的字符集合中
						showCahr.push(str)
						// 添加到页面上
						li.innerHTML = str
						// // 给每一个元素绑定一个标识，为了后面可以精准的清除
						li.setAttribute('data-index', str)
						// 随机改变位置 保证位置不会重复
						let index = getRandom(0, 9)
						while (lastLeftPostion.includes(index)) {
							index = getRandom(0, 9)
						}
						// 记录每次生成的位置
						lastLeftPostion.push(index)
						li.style.left = index * base + 'px'
						// 默认 是 canvas层级最高，将li的层级提升
						li.style.zIndex = 999
						app.appendChild(li)
						// 由于 canvas的层级关系，多以就算是手动点击也不会触发点击事件
						li.addEventListener(
							'click',
							function () {
								var x = li.offsetLeft
								var y = li.offsetTop
								// var x = li.pageX
								// var y = li.pageY
								console.log(x, y)
								createBall(x, y)
							},
							true
						)
						animate(li, 600, downloadingSpeed, 20, function () {
							// 清除元素
							li.parentNode.removeChild(li)
							removeOne(str)
							showGameInfo()
							maxErrorNum-- <= 0 ? over() : maxErrorNum
						})
					}
				}, 1000)
			}
			// 开始游戏
			createChar()
			// 生成26个字母
			function generateBig() {
				var str = []
				for (var i = 65; i < 91; i++) {
					str.push(String.fromCharCode(i))
				}
				return str
			}
			// 生成随机数
			function getRandom(n, m) {
				return Math.floor(Math.random() * (m - n + 1) + n)
			}
			// 封装动画函数
			function animate(obj, target, spped = 5, time = 20, callback) {
				clearInterval(obj.timer)
				obj.timer = setInterval(function () {
					if (obj.offsetTop >= target) {
						clearInterval(obj.timer)
						callback?.()
					}
					obj.style.top = obj.offsetTop + spped + 'px'
				}, time)
			}
			// 移除某个元素
			function removeOne(content) {
				const index = showCahr.findIndex((item) => item == content)
				const index2 = lastLeftPostion.findIndex((item) => item == content)
				if (index) {
					showCahr.splice(index, 1)
				}
				if (index2) {
					lastLeftPostion.splice(index2, 1)
				}
			}
			// 键盘按下事件
			function handeLkeyup() {
				document.addEventListener('keyup', function (e) {
					showGameInfo()
					const code = String.fromCharCode(e.keyCode)
					let enterVal = ''
					app.childNodes.forEach((node) => {
						if (node.nodeType === 1) {
							Array.from(node.attributes).forEach((item) => {
								if (code == item.nodeValue) {
									enterVal = item.nodeValue
									// 用户按了正确的按键 手动触发点击事件
									node.click()
									score++
									// 游戏难度提升
									hard()
									showGameInfo()
									node.parentNode.removeChild(node)
									//数组清除元素
									removeOne(item.nodeValue)
								}
							})
						}
					})
					if (code != enterVal) {
						maxErrorNum-- <= 0 ? over() : maxErrorNum
					}
					if (e.keyCode == 13) {
						// 结束游戏
						over()
					}
				})
			}
			// 显示游戏的标题
			handeLkeyup()
			function showGameInfo() {
				chance.innerHTML = `还有${maxErrorNum}次机会`
				scores.innerHTML = `当前游戏得分${score}`
				currentGamLeve.innerHTML = `游戏难度:${gamLeveTxt}`
				history.innerHTML = `历史最高${TopScore}分`
			}
			showGameInfo()
			// 游戏难度升级升级到 hard
			function hard(callback) {
				gamLeveScore.forEach((item) => {
					if (score >= item.gamLeveScore) {
						gamLeveTxt = item.gamLeve
						downloadingSpeed = item.speed
						maximum = item.maximum
					}
				})
				callback?.callback()
			}
			// 游戏结束
			function over() {
				clearInterval(createCharTimer)
				// 清除页面所有的元素

				if (compare(score, TopScore)) {
					setItem(stroeKdy, score)
				}
				alert(`游戏结束,得分${score}分`)
				app.childNodes.forEach((node) => {
					node.parentNode.removeChild(node)
				})
				// 所属性重置
				score = 0
				showCahr = []
				lastLeftPostion = []
				maxErrorNum = 5
				createCharTimer = null
				gamLeveTxt = '普通'
				downloadingSpeed = 5
				// 信息更新
				showGameInfo()
				location.reload()
			}
			// 本地存储游戏记录相关函数
			function compare(score, TopScore) {
				console.log(score)
				console.log(TopScore)
				console.log(~~score - ~~TopScore)
				return ~~TopScore - ~~score > 0 ? false : true
			}
			function setItem(key, val) {
				window.localStorage.setItem(key, score)
			}
			function getItem(key) {
				return window.localStorage.getItem(key)
			}
			function removeItem(key) {
				window.localStorage.removeItem(key)
			}
		</script>
	</body>
</html>
'
